"""
Author: Jian SuiYue kaohx0214@yeah.net
Date: 2025-05-05 02:13:31
LastEditTime: 2025-05-15 17:08:23
FilePath: LibraryManagerStudio/web/routes/borrow_api.py
"""
import datetime as dt

from fastapi import APIRouter, Depends, HTTPException, status, Query
from fastapi.responses import JSONResponse

from .token_api import validate_jwt
from ..deps import get_db
from ...database import DBManager
from ...datamodel import Borrow, BorrowBase, User, Book, BorrowStatus, BorrowUpdate

router = APIRouter()

"""
/get/{user_id}
/gets
/new
/update
/delete/{borrow_id}
"""


@router.get(path="/get")
async def get_borrow(
        login: str = Query(...),
        user_id: str = Query(..., ge=1),
        db: DBManager = Depends(get_db)
):
    """
    Get borrow record by user_id.
    
    GET /get?login={token}&user_id={user_id}
    Args:
        login: Token.id
        user_id: User.id
        db: DBManager
    """
    validate_jwt(login)
    # check user exist
    user_exist = db.get(User, filters={"id": user_id})
    if not user_exist.data or not user_exist.status:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"User ID {user_id} not found")

    result = db.get(Borrow, filters={"user_id": user_id})
    if not result.status or not result.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Borrow User ID: {user_id} Not found")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "data": result.data, "message": "Get borrow successful"}
    )


@router.post(path="/gets")
async def get_borrows(
        login: str = Query(...),
        page: int = Query(1, ge=1),
        size: int = Query(10, ge=1, le=100),
        db: DBManager = Depends(get_db)
):
    """
    Get borrow records.

    POST /gets?login={your_token}&page={page}&size={size} 
    Args:
        login: Token.id
        page: page
        size: size
        db: DBManager
    """
    validate_jwt(login)
    borrows = db.get(Borrow, page_info={"page": page, "size": size})
    if not borrows.status or not borrows.data:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unexpected Error: {borrows.message}")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "data": borrows.data, "message": "Get borrows successful"}
    )


@router.post("/new")
async def new_borrow(
        borrow_base: BorrowBase,
        login: str = Query(...),
        db: DBManager = Depends(get_db)
):
    """
    Create a new borrow record.
    
    POST /new?login={login}
    Args:
        borrow_base: BorrowBase
        login: Token.id
        db: DBManager
    """
    validate_jwt(login)
    uid, book_id = borrow_base.uid, borrow_base.book_id
    user_exist = db.get(User, filters={"id": uid})

    # 1.verify 
    if not user_exist.status or not user_exist.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"User ID {uid} Not found")

    book_can_borrow = db.get(Book, filters={"id": book_id}).data[0]
    if book_can_borrow['borrow_id']:  # if borrow_id is not none
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f"Book ID {book_id} have been borrowed")

    # 2.setting element    
    created_at, delta = dt.datetime.now(), dt.timedelta(days=borrow_base.borrowing_time)
    borrow = Borrow(user_id=uid, expected_return_time=created_at + delta)
    result = db.upsert(borrow)
    if not result.data or not result.status:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unexpected error at set borrow data")

    # 3.update borrow id at book(borrow_id) table
    book = Book(id=book_id, borrow_id=result.data[0].id)
    res = db.upsert(book)
    if not res.data or not res.status:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST,
                            detail=f"Unexpected error at update book borrow_id")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "data": result.data[0], "message": "New borrow successful"}
    )


@router.put("/update")
async def update_borrow(
        borrow: BorrowUpdate,
        login: str = Query(...),
        db: DBManager = Depends(get_db)
):
    """
    Update borrow record.

    PUT /update?login={your_token}
    Args:
        borrow: Borrow
        login: Token.id
        db: DBManager
    """
    validate_jwt(login)
    borrow_exist = db.get(Borrow, filters={"id": borrow.id})
    if not borrow_exist.status or not borrow_exist.data:  # 主键不能改变
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Borrow ID {borrow.id} not found")

    origin = borrow_exist.data[0]
    for filed, value in borrow.model_dump():
        if value is not None:
            setattr(origin, filed, value)

    response = db.upsert(Borrow(**origin))
    if not response.status:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"UnExpected Error: {response.message}")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "data": response.data[0], "message": "Update borrow successful"}
    )


@router.delete("/delete")
async def delete_book(
        login: str = Query(...),
        borrow_id: int = Query(..., ge=1),
        db: DBManager = Depends(get_db)
):
    """
    Delete book by book_id

    DELETE /delete?login={your_token}&book_id={your_book_id}`
    Args:
        login: Token.id
        borrow_id: Borrow.id
        db: DBManager
    """
    validate_jwt(login)
    borrow = db.get(Borrow, filters={"id": borrow_id})
    if not borrow.status or not borrow.data:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Borrow ID {borrow_id} not found")

    # Book have the borrow_id(foreign_key), set the borrow_id to None
    if borrow.data[0]['status'] != BorrowStatus.RETURNED:  # if not retunred
        origin = db.get(Book, filters={"borrow_id": borrow_id}).data[0]
        origin["borrow_id"] = None
        db.upsert(Book(**origin))  # set borrow_id = None

    result = db.delete(Borrow, filters={"id": borrow_id})
    if not result.status or not result.data:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Unexpected Error: {result.message}")

    return JSONResponse(
        status_code=status.HTTP_200_OK,
        content={"status": True, "message": "Delete borrow successful"}
    )
